package cn.rulian.base.common.interceptor;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import cn.rulian.base.auth.ann.Access;
import cn.rulian.base.auth.service.RoleService;
import cn.rulian.base.common.dto.Message;
import cn.rulian.base.common.dto.UserInfo;
import cn.rulian.base.common.property.BusinessProperty;
import cn.rulian.base.common.util.Dm2;
import cn.rulian.base.common.util.xx;

import com.google.gson.Gson;

/**
 * 权限认证的拦截器（含登录认证、权限认证）
 */
@Component
public class AuthInterceptor implements HandlerInterceptor
{

	@Autowired
	private RoleService roleService;

	@Autowired
	private BusinessProperty pro; //业务参数
	
	private Dm2 dm =new Dm2();

	private static Map<String,String> authMap; //全部权限集合（权限码：角色ID串）
	
	private static List<String> exceptUrls_end = new ArrayList<>(); //除外的URL（不拦截的，以XX结尾的）
	private static List<String> exceptUrls_index = new ArrayList<>(); //除外的URL（不拦截的，包含XX的）
	
	static{
		//以XX结尾的
		exceptUrls_end.add("/"); //根目录
		exceptUrls_end.add("/rulian"); //登录页
		exceptUrls_end.add("/car"); //登录页
		
		exceptUrls_end.add("/login"); //登录动作
		exceptUrls_end.add("/noAccess"); //无权限页
		exceptUrls_end.add("/noSession"); //会话失效页
		exceptUrls_end.add("/four"); //神秘错误
		exceptUrls_end.add("/base/curd/curd/sonConfig"); //CURD代码生成--子配置保存。防止操作时间过长，session过期后无法保存
		//exceptUrls_end.add("/weixin/weixin/weixin/receive"); //微信接入接口
		
		//包含XX的
		exceptUrls_index.add("/logout"); //退出
		//exceptUrls_index.add("/one/file/sharedFile/download"); //文件下载地址
	}
	
	/**
	 * Handler执行之前调用这个方法
	 */
	@Override
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
	{
		
		String url = request.getRequestURI(); //请求URL
		
		//排除例外（以XX结尾的）
		String indexUrl = "base/main/index"; //主页面地址
		for(String str:exceptUrls_end)
		{
			if(url.endsWith(str) && !url.contains(indexUrl))
			{
				return true;
			}
		}

		//排除例外（包含XX的）
		for(String str:exceptUrls_index)
		{
			if(url.indexOf(str) != -1)
			{
				return true;
			}
		}
		
		//登录验证
		HttpSession session = request.getSession();
		UserInfo userInfo = (UserInfo)session.getAttribute("userInfo");
		if(userInfo == null)
		{
			//内部转发（多系统主页面刷新时，用于识别是那一个系统）
			request.getRequestDispatcher("/noSession").forward(request,response); 
			return false;
		}
		
		//版权较验
		java.util.Random rand = new java.util.Random();
		int sjs = rand.nextInt(6);
		if(sjs == 1)
		{
			if(!dm.pass(pro.getKey()))
			{
				response.sendRedirect(request.getContextPath()+"/four");//跳转到超时界面
				return false;
			}
		}
		
		//权限验证
		HandlerMethod hm = (HandlerMethod)handler;
		Class theClass = hm.getBeanType(); //访问的类
		Method theMethod = hm.getMethod(); //访问的方法
		Access acc_class = (Access) theClass.getAnnotation(Access.class); //类注释
		Access acc_method = theMethod.getAnnotation(Access.class); //方法注释
		
		if(authMap == null)
		{
			authMap =  roleService.getAuthMap();
		}
	
		if(acc_class!=null)
		{//类权限验证
			String authCode = acc_class.authCode();
			if(!xx.isEmpty(authCode))
			{
				if(!this.canAccess(userInfo, authCode))
				{
					this.write(request, response);
					return false;
				}
			}
		}
		
		if(acc_method!=null)
		{//方法权限验证
			String authCode = acc_method.authCode();
			if(!xx.isEmpty(authCode))
			{
				if(!this.canAccess(userInfo, authCode))
				{
					this.write(request, response);
		            return false;
				}
			}
		}
		
		return true;
	}

	
	/**
	 * 回写信息
	 */
	private void write(HttpServletRequest request, HttpServletResponse response) throws IOException
	{
		if (request.getHeader("x-requested-with") != null && request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest"))
		{ //ajax请求，则返回错误消息 
			Message msg = new Message();
			msg.setCode(Message._ERROR);
			msg.setMsg("无相关仅限，操作失败！！！");
			Gson gson = xx.getGson();
			
			response.setCharacterEncoding("UTF-8");
		    response.setContentType("application/json;charset=UTF-8");
			PrintWriter out = response.getWriter();  
		    out.print(gson.toJsonTree(msg));//消息
		    
		    out.flush();
		}else{//非ajax请求，则直接跳转
			response.sendRedirect(request.getContextPath()+"/noAccess");
		}
	}
	
	/**
	 * 验证用户是否具有某项权限
	 */
	private boolean canAccess(UserInfo userInfo,String authCode)
	{
		List<Long> roleIds = userInfo.getRoleIds(); //用户拥有的角色ID列表
		if(roleIds == null)
		{//用户没有拥有任何角色
			return false;
		}
		String ids = authMap.get(authCode);
		if(ids == null)
		{//资源没有分配给任何角色
			return false;
		}
		for(Long id:roleIds)
		{
			if(ids.indexOf(","+id.longValue()+",") >= 0)
			{
				return true;
			}
		}
		return false;
	}

	/**
	 * Handler执行之后，ModelAndView返回之前调用这个方法
	 */
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception
	{
	}

	/**
	 * Handler执行完成之后调用这个方法
	 */
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exc) throws Exception
	{
	}

	public static void setAuthMap(Map<String, String> authMap)
	{
		AuthInterceptor.authMap = authMap;
	}

}
